package com.dmgameclient.widget;

import com.dmgameclient.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

/**
 * @name 下拉刷新、上拉加载分页ListView控件
 * @Descripation <br>
 *               1、需要捕获的用户手势：down按下、up抬起、move移动。主要捕获move状态下手指(纵坐标)在屏幕上滑动的距离，
 *               通过计算下滑或上滑的距离decline/increase来改变头部(底部)的状态。
 *               2、列表的5种互斥状态：pull、release
 *               、refreshing、down、back。下拉(上拉)、临界、松手、进入刷新()状态、刷新完成。<br>
 *               3、头部(底部)布局高度随手势变化：初始状态下，头部上边距和底部下边距均为零。下拉头部布局时，头部上边距逐渐增大，
 *               返回时逐渐减小;上拉底部布局时，底部下边距逐渐增大， 返回时逐渐减小。<br>
 *               4、头部(底部)动画效果随手势变化：下拉临界时，头部箭逆置，原路返回时不变;上拉临界时，底部箭头逆置，原路返回时不变。<br>
 *               5、用户事件接口：下拉刷新OnRefreshListener、上拉加载更多分页数据OnLoadMoreListener，
 *               同步更新最近时间。<br>
 * @author 樊俊彬
 * @date 2014-9-24
 * @version 1.0
 */
public class PullListView extends ListView implements OnScrollListener {

	private final static String TAG_HEADER = "HeaderView";
	private final static String TAG_FOOTER = "FooterView";

	// 头部布局及其组件(指示、进度、指示文本、最近更新时间)
	private LinearLayout headerViewLayout;
	private ImageView headerArrowImage;
	private ImageView headerProgressImage;
	private TextView headerTipsText;
	private TextView headerLastUpdateText;

	// 底部布局及其组件
	private LinearLayout footerViewLayout;
	private ImageView footerArrowImage;
	private ImageView footerProgressImage;
	private TextView footerTipsText;
	private TextView footerLastUpdateText;

	// 箭头旋转和逆置、进度条旋转动画
	private RotateAnimation rotateAnimation;
	private RotateAnimation reverseAnimation;
	private Animation progressAnimation;

	// 下拉（上拉）、松手、正在刷新和完成4种状态
	private final static int PULL = 0;
	private final static int RELEASE = 1;
	private final static int REFRESHING = 2;
	private final static int DONE = 3;

	// 标记是否从最头部下拉，最底部上拉
	private boolean isFromFirstItem;
	private boolean isFromLastItem;
	private int firstItemIndex;
	private int lastItemIndex;
	private int curTotalItemCount;

	// 标记是否原路返回
	private boolean isHeaderBack;
	private boolean isFooterBack;

	// 当前状态
	private int headerState = 2;
	private int footerState;

	// 头部视图的上边距、底部视图的下边距
	private int headerTopPadding;
	private int footerBottomPadding;

	// 当前手势的滑动的纵向坐标
	private float headerGestureStartY;
	private float footerGestureStartY;

	// 布局实际高度和指定拉动临界值
	private int viewLayoutHeight;
	private int pullHeighSpec = 100;

	// 头部刷新、底部加载更多用户接口
	public OnRefreshListener onRefreshListener;
	public OnLoadMoreListener onLoadMoreListener;

	public PullListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initAnimation(context);
		initHeaderView(context);
		initFooterViews(context);
		setOnScrollListener(this);
	}

	public PullListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initAnimation(context);
		initHeaderView(context);
		initFooterViews(context);
		setOnScrollListener(this);
	}

	/**
	 * 初始化头部和底部使用的动画效果
	 */
	private void initAnimation(Context context) {

		// 中心旋转180（0，-180）
		rotateAnimation = new RotateAnimation(0, -180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		rotateAnimation.setInterpolator(new LinearInterpolator());
		rotateAnimation.setDuration(100);
		rotateAnimation.setFillAfter(true);

		// 逆置动画（-180，0）
		reverseAnimation = new RotateAnimation(-180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		reverseAnimation.setInterpolator(new LinearInterpolator());
		reverseAnimation.setDuration(100);
		reverseAnimation.setFillAfter(true);

		// 进度条旋转动画
		progressAnimation = AnimationUtils.loadAnimation(context,
				R.anim.loading_rotate_anim);
	}

	/**
	 * 加载头部所有组件(箭头图标、圆圈进度条、提示文本、最后一次更新时间),设置初始大小和样式
	 */
	private void initHeaderView(Context context) {
		headerViewLayout = (LinearLayout) LayoutInflater.from(context).inflate(
				R.layout.header_footer_list_view, null);

		headerArrowImage = (ImageView) headerViewLayout
				.findViewById(R.id.arrow_image);
		headerArrowImage.setMinimumWidth(50);
		headerArrowImage.setMinimumHeight(50);
		headerProgressImage = (ImageView) headerViewLayout
				.findViewById(R.id.progress_image);
		headerTipsText = (TextView) headerViewLayout
				.findViewById(R.id.tips_text);
		headerLastUpdateText = (TextView) headerViewLayout
				.findViewById(R.id.last_updated_text);
		headerViewLayout.measure(0, 0);

		headerViewLayout.measure(0, 0);

		viewLayoutHeight = headerViewLayout.getMeasuredHeight();

		// 初始边距为负值，即为隐藏状态
		headerTopPadding = headerViewLayout.getPaddingTop();
		headerViewLayout.setPadding(headerViewLayout.getPaddingLeft(), -1
				* viewLayoutHeight, headerViewLayout.getPaddingRight(),
				headerViewLayout.getPaddingBottom());
		headerViewLayout.invalidate();
		addHeaderView(headerViewLayout);
		changeHeaderViewByState();
	}

	/**
	 * 加载底部所有组件(箭头图标、圆圈进度条、提示文本、最后一次更新时间),设置初始大小和样式
	 */
	private void initFooterViews(Context context) {
		footerViewLayout = (LinearLayout) LayoutInflater.from(context).inflate(
				R.layout.header_footer_list_view, null);
		footerArrowImage = (ImageView) footerViewLayout
				.findViewById(R.id.arrow_image);
		footerArrowImage.setMinimumWidth(50);
		footerArrowImage.setMinimumHeight(50);
		footerProgressImage = (ImageView) footerViewLayout
				.findViewById(R.id.progress_image);
		footerTipsText = (TextView) footerViewLayout
				.findViewById(R.id.tips_text);
		footerLastUpdateText = (TextView) footerViewLayout
				.findViewById(R.id.last_updated_text);

		footerViewLayout.measure(0, 0);

		// 初始边距为负值，即为隐藏状态
		footerBottomPadding = footerViewLayout.getPaddingBottom();
		footerViewLayout.setPadding(footerViewLayout.getPaddingLeft(),
				footerViewLayout.getPaddingTop(),
				footerViewLayout.getPaddingRight(), -1 * viewLayoutHeight);
		footerViewLayout.invalidate();
		addFooterView(footerViewLayout);
	}

	/**
	 * 监听列表滚动,记录列表的第一项和最后一项(为头部刷新和底部刷新提供依据)
	 */
	public void onScroll(AbsListView view, int firstVisiableItem,
			int visibleItemCount, int totalItemCount) {
		firstItemIndex = firstVisiableItem;
		lastItemIndex = firstVisiableItem + visibleItemCount;
		curTotalItemCount = totalItemCount;
	}

	public void onScrollStateChanged(AbsListView view, int scrollState) {
	}

	/**
	 * 捕获手势，计算滑动距离来改变列表状态
	 */
	public boolean onTouchEvent(MotionEvent event) {

		switch (event.getAction()) {

		case MotionEvent.ACTION_MOVE:

			// 从头开始向下滑动并记录下滑起始位置
			if (!isFromFirstItem && firstItemIndex == 0) {
				isFromFirstItem = true;
				headerGestureStartY = event.getY();
			}

			// 从底开始上滑并记录上滑起始位置
			if (!isFromLastItem && (lastItemIndex == curTotalItemCount)) {
				isFromLastItem = true;
				footerGestureStartY = event.getY();
			}

			// 从头部开始滑动且当前状态处于‘非’正在刷新REFRESHING状态（pull,release,done三种状态互斥）时
			if (headerState != REFRESHING && isFromFirstItem) {
				// 手势下滑程度
				float decline = event.getY() - headerGestureStartY;
				listenHeaderStateChanged(decline);
			}

			// 从底部开始上滑且当前状态处于‘非’正在刷新REFRESHING状态（pull,release,done三种状态互斥）时
			if (footerState != REFRESHING && isFromLastItem) {
				// 手势上滑程度
				float increase = footerGestureStartY - event.getY();
				listenFooterStateChanged(increase);
			}

			break;

		// 手势抬起时会出现三种不同的状态(release,done,pull)
		case MotionEvent.ACTION_UP:

			// 头部
			if (headerState != REFRESHING) {
				if (headerState == DONE) {
				} else if (headerState == PULL) {
					headerState = DONE;
					changeHeaderViewByState();
				} else if (headerState == RELEASE) {
					headerState = REFRESHING;
					changeHeaderViewByState();
					onRefresh();
				}
			}
			isFromFirstItem = false;
			isHeaderBack = false;

			// 底部
			if (footerState != REFRESHING) {
				if (footerState == DONE) {
				} else if (footerState == PULL) {
					footerState = DONE;
					changeFooterViewByState();
				} else if (footerState == RELEASE) {
					footerState = REFRESHING;
					changeFooterViewByState();
					onLoadMore();
				}
			}
			isFromLastItem = false;
			isFooterBack = false;
			break;
		}
		return super.onTouchEvent(event);
	}

	/**
	 * 监听头部状态随手势下滑程度的变化
	 * 
	 * @param decline
	 */
	private void listenHeaderStateChanged(float decline) {
		// 当前状态：下拉刷新（0 < decline < 指定高度）
		if (headerState == PULL) {
			if (decline >= viewLayoutHeight + pullHeighSpec) {
				headerState = RELEASE;
				isHeaderBack = true;
				changeHeaderViewByState();
			} else if (decline <= 0) {
				headerState = DONE;
				changeHeaderViewByState();
			}
		}

		// 当前状态：松手刷新(decline >= 指定高度时)
		else if (headerState == RELEASE) {
			if (decline > 0 && decline < (viewLayoutHeight + pullHeighSpec)) {
				headerState = PULL;
				changeHeaderViewByState();
			} else if (decline <= 0) {
				headerState = DONE;
				changeHeaderViewByState();
			}
		}

		// 当前状态：完成(decline = 0)
		else if (headerState == DONE) {
			if (decline > 0) {
				headerState = PULL;
				changeHeaderViewByState();
			}
		}

		// 根据不同的状态来改变头部布局的上边距，达到头部跟随手势一起下滑的效果
		// 下拉刷新状态下：上边距逐渐增大
		if (headerState == PULL) {
			int topPadding = (int) ((-1 * viewLayoutHeight + (decline)));
			headerViewLayout.setPadding(headerViewLayout.getPaddingLeft(),
					topPadding, headerViewLayout.getPaddingRight(),
					headerViewLayout.getPaddingBottom());
			headerViewLayout.invalidate();
		}

		// 松手刷新状态下：上边距逐渐减小
		if (headerState == RELEASE) {
			int topPadding = (int) ((decline - viewLayoutHeight));
			headerViewLayout.setPadding(headerViewLayout.getPaddingLeft(),
					topPadding, headerViewLayout.getPaddingRight(),
					headerViewLayout.getPaddingBottom());
			headerViewLayout.invalidate();
		}
	}

	/**
	 * 监听底部状态随手势下滑程度的变化
	 */
	private void listenFooterStateChanged(float increase) {

		// 当前状态：上拉刷新（0 < increase < 指定高度）
		if (footerState == PULL) {
			if (increase >= viewLayoutHeight + pullHeighSpec) {
				footerState = RELEASE;
				isFooterBack = true;
				changeFooterViewByState();
			} else if (increase <= 0) {
				footerState = DONE;
				changeFooterViewByState();
			}
		}

		// 当前状态：松手刷新(increase >= 指定高度时)
		else if (footerState == RELEASE) {
			if (increase > 0 && increase < (viewLayoutHeight + pullHeighSpec)) {
				footerState = PULL;
				changeFooterViewByState();
			} else if (increase <= 0) {
				footerState = DONE;
				changeFooterViewByState();
			}
		}

		// 当前状态：完成(increase <= 0)
		else if (footerState == DONE) {
			if (increase > 0) {
				footerState = PULL;
				changeFooterViewByState();
			}
		}

		// 根据不同的状态来改变底部布局的下边距，达到头部跟随手势一起上滑的效果
		// 下拉刷新状态下：上边距逐渐增大
		if (footerState == PULL) {
			int bottomPaddding = (int) ((-1 * viewLayoutHeight + (increase)));
			footerViewLayout.setPadding(footerViewLayout.getPaddingLeft(),
					footerViewLayout.getPaddingTop(),
					footerViewLayout.getPaddingRight(), bottomPaddding);
			footerViewLayout.invalidate();
		}

		// 松手刷新状态下：上边距逐渐减小
		if (footerState == RELEASE) {
			int bottomPadding = (int) ((increase - viewLayoutHeight));
			footerViewLayout.setPadding(footerViewLayout.getPaddingLeft(),
					footerViewLayout.getPaddingTop(),
					footerViewLayout.getPaddingRight(), bottomPadding);
			footerViewLayout.invalidate();
		}
	}

	/**
	 * 根据当前状态同步刷新头部界面
	 */
	private void changeHeaderViewByState() {
		switch (headerState) {

		// 下拉刷新：除进度条外全部显示
		case PULL:
			headerArrowImage.setVisibility(View.VISIBLE);
			headerArrowImage.clearAnimation();
			if (isHeaderBack) {
				isHeaderBack = false;
				headerArrowImage.clearAnimation();
				headerArrowImage.startAnimation(reverseAnimation);
			}
			headerProgressImage.clearAnimation();
			headerProgressImage.setVisibility(View.GONE);
			headerTipsText.setVisibility(View.VISIBLE);
			headerTipsText.setText("下拉刷新");
			headerLastUpdateText.setVisibility(View.VISIBLE);
			break;

		// 松手刷新：除进度条外全部显示
		case RELEASE:
			headerArrowImage.setVisibility(View.VISIBLE);
			headerArrowImage.clearAnimation();
			headerArrowImage.startAnimation(rotateAnimation);
			headerProgressImage.clearAnimation();
			headerProgressImage.setVisibility(View.GONE);
			headerTipsText.setVisibility(View.VISIBLE);
			headerTipsText.setText("松手刷新");
			headerLastUpdateText.setVisibility(View.VISIBLE);
			break;

		// 正在刷新：隐藏指示图标、显示加载进度条
		case REFRESHING:
			headerViewLayout.setPadding(headerViewLayout.getPaddingLeft(),
					headerTopPadding, headerViewLayout.getPaddingRight(),
					headerViewLayout.getPaddingBottom());
			headerViewLayout.invalidate();
			headerArrowImage.clearAnimation();
			headerArrowImage.setVisibility(View.GONE);
			headerProgressImage.setVisibility(View.VISIBLE);
			headerProgressImage.startAnimation(progressAnimation);
			headerTipsText.setText("正在拼命加载...");
			headerLastUpdateText.setVisibility(View.GONE);
			break;

		// 完成：恢复原样
		case DONE:
			headerViewLayout.setPadding(headerViewLayout.getPaddingLeft(), -1
					* viewLayoutHeight, headerViewLayout.getPaddingRight(),
					headerViewLayout.getPaddingBottom());
			headerViewLayout.invalidate();
			headerArrowImage.clearAnimation();
			headerArrowImage.setImageResource(R.drawable.ic_pull_arrow_down);
			headerProgressImage.clearAnimation();
			headerProgressImage.setVisibility(View.GONE);
			headerTipsText.setText("下拉刷新");
			headerLastUpdateText.setVisibility(View.VISIBLE);
			break;
		}
	}

	/**
	 * 根据当前状态同步刷新底部界面
	 */
	private void changeFooterViewByState() {
		switch (footerState) {

		// 上拉刷新、除进度条隐藏、箭头向下
		case PULL:
			footerArrowImage.setVisibility(View.VISIBLE);
			footerArrowImage.startAnimation(rotateAnimation);
			if (isFooterBack) {
				isFooterBack = false;
				footerArrowImage.clearAnimation();
			}
			footerProgressImage.clearAnimation();
			footerProgressImage.setVisibility(View.GONE);
			footerTipsText.setVisibility(View.VISIBLE);
			footerTipsText.setText("上拉加载更多");
			footerLastUpdateText.setVisibility(View.VISIBLE);
			break;

		// 松手刷新：除进度条外全部显示
		case RELEASE:
			footerArrowImage.setVisibility(View.VISIBLE);
			footerArrowImage.startAnimation(reverseAnimation);
			footerProgressImage.clearAnimation();
			footerProgressImage.setVisibility(View.GONE);
			footerTipsText.setVisibility(View.VISIBLE);
			footerTipsText.setText("松手加载");
			footerLastUpdateText.setVisibility(View.VISIBLE);
			break;

		// 正在刷新：隐藏指示图标、显示加载进度条
		case REFRESHING:
			footerViewLayout.setPadding(footerViewLayout.getPaddingLeft(),
					footerViewLayout.getPaddingTop(),
					footerViewLayout.getPaddingRight(), footerBottomPadding);
			footerViewLayout.invalidate();
			footerArrowImage.clearAnimation();
			footerArrowImage.setVisibility(View.GONE);
			footerProgressImage.setVisibility(View.VISIBLE);
			footerProgressImage.startAnimation(progressAnimation);
			footerTipsText.setText("正在拼命加载...");
			footerLastUpdateText.setVisibility(View.GONE);
			break;

		// 完成：恢复原样
		case DONE:
			footerViewLayout.setPadding(footerViewLayout.getPaddingLeft(),
					footerViewLayout.getPaddingTop(),
					footerViewLayout.getPaddingRight(), -1 * viewLayoutHeight);
			footerViewLayout.invalidate();
			footerArrowImage.clearAnimation();
			footerArrowImage.setImageResource(R.drawable.ic_pull_arrow_down);
			footerProgressImage.clearAnimation();
			footerProgressImage.setVisibility(View.GONE);
			footerTipsText.setText("上拉加载更多");
			footerLastUpdateText.setVisibility(View.VISIBLE);
			break;
		}
	}

	/**
	 * 进入头部刷新状态时，执行用户指定操作
	 */
	private void onRefresh() {
		if (onRefreshListener != null) {
			onRefreshListener.onRefresh();
		}
	}

	/**
	 * 进入底部加载更多状态时，执行用户指定的操作
	 */
	private void onLoadMore() {
		if (onLoadMoreListener != null) {
			onLoadMoreListener.onLoadMore();
		}
	}

	/**
	 * 用户调用此方法，注入头部刷新接口的子类对象
	 * 
	 * @param refreshListener
	 */
	public void setOnRefreshListener(OnRefreshListener refreshListener) {
		this.onRefreshListener = refreshListener;
	}

	/**
	 * 用户调用此方法，注入底部加载更多接口的子类对象
	 * 
	 * @param loadMoreListener
	 */
	public void setOnLoadMoreListener(OnLoadMoreListener loadMoreListener) {
		this.onLoadMoreListener = loadMoreListener;
	}

	/**
	 * 用户调用此方法，注入头部刷新操作完成时的时间
	 */
	public void onRefreshComplete(String update) {
		headerLastUpdateText.setText(update);
		onRefreshComplete();
	}

	public void onRefreshComplete() {
		headerState = DONE;
		changeHeaderViewByState();
	}

	/**
	 * 用户调用此方法，注入头部刷新操作完成时的时间
	 */
	public void onLoadMoreComplete(String update) {
		footerLastUpdateText.setText(update);
		footerState = DONE;
		changeFooterViewByState();
	}

	public void onLoadMoreComplete() {
		footerState = DONE;
		changeFooterViewByState();
	}
}